package de.koller.oceanFramework.gl.util;

import de.koller.oceanFramework.gl.OceanGame;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.TitledBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.lwjgl.opengl.Display;
import org.lwjgl.opengl.DisplayMode;
import org.lwjgl.opengl.GL11;

/**
 * Interne Klasse genutzt bei {@link OceanGame}.
 * @see OceanGame
 * @author Fabian Koller 
 * @since Aug 2011 */
public class DisplayModeChooser extends JFrame {
	private static final long serialVersionUID = 1L;

	private final ArrayList<DisplayMode> modes = new ArrayList<>();
	private final List<ButtonChoose> chooses = new ArrayList<>();
	
	private DisplayMode dmode = null;
	private boolean dfs = false;
	private boolean vsync = false;
	
	private JComboBox<ButtonChoose> comboBox = new JComboBox<>();
	private JCheckBox cvsynch = new JCheckBox( "Vertikale Synchronisation" );
	private JCheckBox cfullscreen = new JCheckBox( "Vollbild" );
	private JCheckBox cFilter = new JCheckBox( "weiche Texturen" );
	private JButton cstart = new JButton( "starten" );
	
	private JTextField cipadress = new JTextField();
	private JCheckBox casClient = new JCheckBox( "mit Server verbinden" );
	
	/** */
	public DisplayModeChooser() {
		super(); 
		
		try {
			List<Image> icons = new ArrayList<>();
			ClassLoader cl = this.getClass().getClassLoader();
			icons.add( ImageIO.read( cl.getResourceAsStream( "data/icons/icon164.png" ) ) );
			icons.add( ImageIO.read( cl.getResourceAsStream( "data/icons/icon132.png" ) ) );
			icons.add( ImageIO.read( cl.getResourceAsStream( "data/icons/icon116.png" ) ) );
			this.setIconImages( icons );
		} catch( Exception ex ) {
			System.err.println( ex );
		}
		
		this.setLayout( new GridBagLayout() );
		
		try {
			initModes();
			for( DisplayMode dm : modes ) {
				ButtonChoose c = new ButtonChoose( dm );
				chooses.add( c );
				comboBox.addItem( c );
			}
		} catch ( Exception e ) {
			System.err.println( e );
		}
		
		comboBox.setToolTipText( "Auflösung in der das Spiel gestartet wird." );
		cfullscreen.setToolTipText( "Starte Spiel im Vollbild" );
		cvsynch.setToolTipText( "Verhindert eine aktualisierung des Bildschirms während des Aufbaus" );
		cstart.setToolTipText( "Startet das Spiel" );
		cFilter.setToolTipText( "Sollen die Texturen weich gezeichnet werden oder pixelig(schneller)" );
		
		cfullscreen.addChangeListener( new FullscreenChange() );
		cfullscreen.setSelected( false );
		cvsynch.setEnabled( false );
		
		try {
			cipadress.setText( InetAddress.getLocalHost().getHostAddress() );
		} catch ( UnknownHostException ex ) {
			casClient.setEnabled( false );
		}
		casClient.setEnabled( OceanGame.enableClientChoose );
		cipadress.setEnabled( false );
		casClient.addChangeListener( new ClientChange() );
		
		cFilter.setSelected( true );
		
		JPanel pd = new JPanel( new GridLayout( 0, 1 ) );
		pd.add( comboBox );
		pd.add( cvsynch );
		pd.add( cfullscreen );
		pd.add( cFilter );
		pd.setBorder( new TitledBorder( "Bildschirm" ) );
		GridBagConstraints cbgd = new GridBagConstraints();
		cbgd.gridx = 0;
		cbgd.gridy = 0;
		cbgd.fill = GridBagConstraints.HORIZONTAL;
		this.add( pd, cbgd );
		
		JPanel md = new JPanel( new GridLayout( 0, 1 ) );
		md.setEnabled( false );
		md.add( cipadress );
		md.add( casClient );
		casClient.setEnabled( OceanGame.enableClientChoose );
		md.setBorder( new TitledBorder( "Netzwerk" ) );
		GridBagConstraints cbgn = new GridBagConstraints();
		cbgn.gridx = 0;
		cbgn.gridy = 1;
		cbgn.fill = GridBagConstraints.HORIZONTAL;
		cbgn.insets.top = 20;
		this.add( md, cbgn );
		
		GridBagConstraints bs = new GridBagConstraints();
		bs.gridx = 0;
		bs.gridy = 2;
		bs.fill = GridBagConstraints.HORIZONTAL;
		bs.insets.top = 20;
		this.add( cstart, bs );
		
		cstart.addActionListener( new Starter() );
		
		this.pack();
		
		this.setLocation( (int)Toolkit.getDefaultToolkit().getScreenSize().getWidth() / 2 - this.getWidth()/2, 
				(int)Toolkit.getDefaultToolkit().getScreenSize().getHeight()/2 - this.getHeight()/2 );
		
		this.setTitle( "Starten" );
		this.setResizable( false );
		this.setVisible( true );
		this.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );

		cstart.requestFocus();
		
		cFilter.setEnabled( false );
	}
	
	/** Setzt erwünschte voreingestellte Werte fest.
	 * @param width 
	 * @param filter
	 * @param height 
	 * @param freq 
	 * @param depth 
	 * @param full  
	 */
	public void setWished( int width, int height, int depth, int freq, boolean filter, boolean full ) {
		if( filter == false ) {
			cFilter.setSelected( false );
			cFilter.setEnabled( false );
		}
		cfullscreen.setSelected( full );
		
		for( ButtonChoose o : chooses ) {
			if( !o.is( width, height, depth, freq ) )
				continue;
			
			comboBox.setSelectedItem( o );
			comboBox.setEnabled( false );
			break;
		}
	}
	
	private void initModes() throws Exception {
		Collections.addAll( modes, Display.getAvailableDisplayModes() );
		Collections.sort( modes, new Comparator<DisplayMode>() {

			@Override
			public int compare( DisplayMode o1, DisplayMode o2 ) {
				int c = new Integer( o2.getWidth() ).compareTo( o1.getWidth() );
				if( c != 0 )
					return c;
				
				c = new Integer( o2.getHeight() ).compareTo( o1.getHeight() );
				if( c != 0 )
					return c;
				
				c = new Integer( o2.getBitsPerPixel() ).compareTo( o1.getBitsPerPixel() );
				if( c != 0 )
					return c;
				
				return new Integer( o2.getFrequency() ).compareTo( o1.getFrequency() );
			}
			
		});
	}
	
	/**
	 * @return 
	 */
	public DisplayMode getChoosedMode() {
		return dmode;
	}
	
	/**
	 * @return 
	 */
	public boolean isFullscreen() {
		return dfs;
	}
	
	/**
	 * @return 
	 */
	public boolean isVsync() {
		return vsync;
	}
	
	/**
	 * @return 
	 */
	public boolean isAsClient() {
		return casClient.isSelected();
	}
	
	/**
	 * @return 
	 */
	public String getIP() {
		return cipadress.getText();
	}
	
	/** */
	private class FullscreenChange implements ChangeListener {

		@Override
		public void stateChanged( ChangeEvent e ) {
			boolean s = ((JCheckBox)e.getSource()).isSelected();
			cvsynch.setEnabled( s );
			if( !s )
				cvsynch.setSelected( false );
		}
		
	}
	
	/** */
	private class ClientChange implements ChangeListener {

		@Override
		public void stateChanged( ChangeEvent e ) {
			boolean s = ((JCheckBox)e.getSource()).isSelected();
			cipadress.setEnabled( s );
			if( !s )
				try {
					cipadress.setText( InetAddress.getLocalHost().getHostAddress() );
				} catch ( UnknownHostException ex ) {
					
				}
		}
		
	}
	
	private class ButtonChoose {

		private final DisplayMode mode;

		public ButtonChoose( DisplayMode mode /*, boolean fs */ ) {
			this.mode = mode;
		}

		@Override
		public String toString() {
			return mode.getWidth() + " x " + mode.getHeight() + " x " +
					mode.getBitsPerPixel() + "  (" + mode.getFrequency() + "Hz)";
		}

		public boolean is( int width, int height, int depth, int freq ) {
			if( width != mode.getWidth() )
				return false;
			if( height != mode.getHeight() )
				return false;
			if( depth != mode.getBitsPerPixel() )
				return false;
			if( freq != mode.getFrequency() )
				return false;
			return true;
		}
	}
	
	private class Starter implements ActionListener {

		@Override
		public void actionPerformed( ActionEvent e ) {
			dmode = ((ButtonChoose)comboBox.getSelectedItem()).mode;
			dfs = cfullscreen.isSelected();
			vsync = cvsynch.isSelected();
			
			synchronized( DisplayModeChooser.this ) {
				DisplayModeChooser.this.notifyAll();
			}
			
			DisplayModeChooser.this.dispose();
		}
		
	}
	
}
